namespace LiteNetLib
{
	internal sealed class SequencedChannel : BaseChannel
	{
		private int _localSequence;

		private ushort _remoteSequence;

		private readonly bool _reliable;

		private NetPacket _lastPacket;

		private readonly NetPacket _ackPacket;

		private bool _mustSendAck;

		public SequencedChannel(NetPeer peer, bool reliable)
			: base(peer)
		{
			_reliable = reliable;
			if (_reliable)
			{
				_ackPacket = new NetPacket(PacketProperty.AckReliableSequenced, 0);
			}
		}

		public override void SendNextPackets()
		{
			if (_reliable && OutgoingQueue.Count == 0)
			{
				NetPacket lastPacket = _lastPacket;
				if (lastPacket != null)
				{
					Peer.SendUserData(lastPacket);
				}
			}
			else
			{
				lock (OutgoingQueue)
				{
					while (OutgoingQueue.Count > 0)
					{
						NetPacket netPacket = OutgoingQueue.Dequeue();
						_localSequence = (_localSequence + 1) % 32768;
						netPacket.Sequence = (ushort)_localSequence;
						Peer.SendUserData(netPacket);
						if (_reliable && OutgoingQueue.Count == 0)
						{
							_lastPacket = netPacket;
						}
						else
						{
							Peer.Recycle(netPacket);
						}
					}
				}
			}
			if (_reliable && _mustSendAck)
			{
				_mustSendAck = false;
				_ackPacket.Sequence = _remoteSequence;
				Peer.SendUserData(_ackPacket);
			}
		}

		public void ProcessAck(NetPacket packet)
		{
			if (_lastPacket != null && packet.Sequence == _lastPacket.Sequence)
			{
				_lastPacket = null;
			}
		}

		public override void ProcessPacket(NetPacket packet)
		{
			int num = NetUtils.RelativeSequenceNumber(packet.Sequence, _remoteSequence);
			if (packet.Sequence < 32768 && num > 0)
			{
				Peer.Statistics.PacketLoss += (ulong)(num - 1);
				_remoteSequence = packet.Sequence;
				Peer.AddIncomingPacket(packet);
			}
			_mustSendAck = true;
		}
	}
}
